package org.kaer.election.trade;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.widget.Toast;

import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;
import org.kaer.election.application.ElectionVoteApplication;
import org.kaer.election.bean.Candidate;
import org.kaer.election.bean.CommandBase;
import org.kaer.election.bean.ReadRecordBean;
import org.kaer.election.bean.SearchVoteBean;
import org.kaer.election.bean.SearchVoter;
import org.kaer.election.bean.SelectedElection;
import org.kaer.election.bean.WriteRecordBean;
import org.kaer.election.utils.CommonUtil;
import org.kaer.election.utils.JSONKeys;
import org.kaer.election.utils.LogUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class ExampleClient {
    private static ExampleClient mExampleClient;
    private static int mport = 6310;
    private Gson gson = new Gson();

    private Socket socket = new Socket();
    private WebSocketClient androidClient;
    public volatile int istart = 0; // 選舉是否開始
    private Context mContext = null;
    private ElectionVoteApplication app = null;
    private HandlerThread mHandlerThread;
    private Handler mHandler;
    private CountDownLatch mLatcher;
    private int CONNECT_STATE;
    public final int STATE_CONNECTED = 0X100;
    public final int STATE_CONNECTEMPTY = 0X101;

    private volatile int iDestroy = 0;
    private volatile int iToastShow = 0;

    public static final int ONOPEN = 0x20;
    public static final int ONCLOSE = 0x21;
    public static final int ONERROR = 0x22;
    public static final int ONMESSAGE = 0x23;

    public static final int Success = 0;
    public static final int NoLogin = 1;
    public static final int TypeError = 2;//消息类型错误
    public static final int AlreadyVoted = 3; //已经投过票了
    public static final int ElectionError = 4;
    //2016112 lizj add flag,whether or not send broadcast; [S]
    private boolean allwoBrocast;

    //2016112 lizj add flag,whether or not send broadcast; [E]
    private ExampleClient() {

    }

    public static ExampleClient getInstance() {
        if (mExampleClient == null)
            mExampleClient = new ExampleClient();

        return mExampleClient;
    }


    public class WsSendThread implements Runnable {
        private String strdata = "";

        public WsSendThread(String data6) {
            strdata = data6;
        }

        @Override
        public void run() {
            // TODO Auto-generated method stub
            clientSendMsg(strdata);

        }

    }

    public int getConnectState() {
        return CONNECT_STATE;
    }

    class ReadHandler extends Handler {
        public ReadHandler() {

        }

        public ReadHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            switch (msg.what) {
                case WebSocketClient.ONOPEN:
                    LogUtils.i("websocket open");
                    // 40.151 ad2951cab072dd32c620182534b07564 0.181
                    // e10adc3949ba59abbe56e057f20f883es
                    // clientLogin("admin", "e10adc3949ba59abbe56e057f20f883e");
                    onOpen();
                    break;
                case WebSocketClient.ONCLOSE:
                    onClose(msg.arg1, msg.obj.toString());
                    break;
                case WebSocketClient.ONERROR:
                    onError((Exception) msg.obj);
                    break;
                case WebSocketClient.ONMESSAGE:
                    onMessage(msg.obj.toString());
                    break;
                default:
                    break;
            }
        }
    }

    public int connectServer(String ip, int port, Context context) {
        try {
            URI url = new URI("ws://" + ip + ":" + port);
            return connectServer(url, context);
        } catch (URISyntaxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return CONNECT_STATE;
    }

    public int connectServer(final URI serverURI, Context context) {

        mContext = context;
        app = (ElectionVoteApplication) ((Activity) mContext).getApplication();
        mHandlerThread = new HandlerThread("election");
        mHandlerThread.start();
        mHandler = new ReadHandler(mHandlerThread.getLooper());
        new Thread(new Runnable() {
            public void run() {
                androidClient = new WebSocketClient(serverURI, mHandler, null);
                androidClient.connect();
            }
        }).start();
        launchTimer();
        return CONNECT_STATE;
    }

    public void disconnectServer() {
        if (androidClient != null)
            androidClient.close();

    }

    public void launchTimer() {
        launchTimer(5);
    }

    public void launchTimer(int seconds) {
        mLatcher = new CountDownLatch(1);
        try {
            mLatcher.await(seconds, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    protected void cancelLatch() {
        try {
            // 上报读取结果
            // nothing
        } finally {
            if (mLatcher != null) {
                mLatcher.countDown();
                mLatcher = null;
            }
        }
    }

    public void onOpen() {
        // TODO Auto-generated method stub
        allwoBrocast = true;
        CONNECT_STATE = STATE_CONNECTED;
        istart = 0;
        cancelLatch();
    }

    private static final String DYNAMICACTION = "org.kaer.utils.ExampleClient"; // 动态广播的Action字符串

    // 解析接收的消息 将解析的消息返回界面

    public void onMessage(String message) {
        try {
            WsReceiveThread wsreceivethread1 = new WsReceiveThread(message, 4);
            new Thread(wsreceivethread1).start();
        } catch (Exception e) {
            // TODO: handle exception
        }

    }

    public class WsReceiveThread implements Runnable {
        private String message = "";
        private volatile int ireceivetype = 0;

        public WsReceiveThread(String data6, int type) {
            ireceivetype = type;
            message = data6;
        }

        @Override
        public void run() {
            // TODO Auto-generated method stub
            try {

                // System.out.println(message);
                // 解析服务器发来的数据 if type 执行相应的代码
                CommandBase info = gson.fromJson(message, CommandBase.class);
                if (info.getType().equalsIgnoreCase("selectedElection")) {

                    // 读取选票
                    election = onSelectedElection(message);
                    cancelLatch();

                } else if (info.getType().equalsIgnoreCase("writeRecord")) {

                    onWriteRecordResult(message);
                } else if (info.getType().equalsIgnoreCase("readRecord")) {
                    // Toast.makeText(app.context4, message,
                    // Toast.LENGTH_SHORT).show();

                    // WsReceiveThread wsreceivethread1 = new
                    // WsReceiveThread(message, 5);
                    // new Thread(wsreceivethread1).start();
                    onReadRecordResult(message);
                } else if (info.getType().equalsIgnoreCase("searchVoter")) {
                    // WsReceiveThread wsreceivethread1 = new
                    // WsReceiveThread(message, 4);
                    // new Thread(wsreceivethread1).start();
                    onSearchVoterResult(message);
                } else {
                }
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    }

    public String getErrorMessage(int code) {
        switch (code) {
            case Success:
                return "操作成功";
            case NoLogin:
                return "未登陆";
            case TypeError:
                return "消息类型错误";
            case AlreadyVoted:
                return "不能重复投票";
            case ElectionError:
                return "选举服务繁忙";
            case -1:
                return "选举服务繁忙,未响应";
        }
        return "未知错误";
    }

    /**
     * 保存到SD卡
     *
     * @param filename
     * @param filecontent
     * @throws Exception
     */
    public void saveToSDCard(String filename, String filecontent) throws Exception {
        File file = new File(Environment.getExternalStorageDirectory(), filename);
        FileOutputStream outStream = new FileOutputStream(file);
        outStream.write(filecontent.getBytes());
        outStream.close();/**
         * FileOutputStream
         */

    }

    public synchronized void onError(Exception ex) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        // ex.printStackTrace();
        // sw.toString().toUpperCase();

        // if the error is fatal then onClose will be called additionally
        String strerror = exceptionstring(ex);
        // sendBroadcast(app.DYNAMICACTIONWEBSOCKET, "1", strerror);
        LogUtils.i("onError ------------------------------------------" + strerror);
        notifyUIClose();
    }

    public synchronized void onClose(int code, String reason) {
        // TODO Auto-generated method stub
        CONNECT_STATE = STATE_CONNECTEMPTY;
        istart = 0;
        LogUtils.i("onClose allowBroadcast "+allwoBrocast);
        notifyUIClose();
    }
    private synchronized void notifyUIClose(){
        if (allwoBrocast) {  //onClose may be call server times
            Intent intent = new Intent("websocket_closed");
            mContext.sendBroadcast(intent); // 发送Intent
            allwoBrocast = !allwoBrocast;
        }
    }
    public void clientSendMsg(String msg) {
        if (androidClient != null) {
            LogUtils.i("client send msg " + msg);
            androidClient.send(msg);
        }
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////
    // 发广播消息给窗体
    private void sendBroadcast(String action, String... msg) {
        String[] strmsg = {"count", "msg", "msga", "msgb", "msgc", "msgd", "msge"};
        Intent intent = new Intent();
        intent.setAction(action); // 设置Action
        int i3 = 0;
        for (i3 = 0; i3 < msg.length; i3++) {
            intent.putExtra(strmsg[i3], msg[i3]); // 添加附加信息
        }
        mContext.sendBroadcast(intent); // 发送Intent
    }

    // 1、获取投票信息： 投票服务-->写票软件
    public SelectedElection onSelectedElection(String message) {
        // 解析字符串 selectedElection 对象
        // json转为简单Bean
        SelectedElection election = null;
        try {
            election = gson.fromJson(message, SelectedElection.class);

        } catch (Exception e) {
            // TODO: handle exception
            Toast.makeText(mContext, "onselecteddelection error", Toast.LENGTH_SHORT).show();
        }

        return election;
    }

    // 2、写票操作 投票服务-->写票软件
    public void onWriteRecordResult(String message) {
        // 解析字符串 selectedElection 对象
        // json转为简单Bean
        try {
            JSONObject jObject = new JSONObject(message);
            writeRecordResult = CommonUtil.GetJsonIntValue(jObject, JSONKeys.Voter.ResultCode, -1);

        } catch (JSONException e) {
            e.printStackTrace();
        }
        cancelLatch();
        // 根據 resultCode判斷寫票
    }

    // 3、读已写的票 投票服务-->写票软件
    public void onReadRecordResult(String message) {
        // 解析字符串 selectedElection 对象
        // json转为简单Bean

        readRecordResult = message;
        cancelLatch();

    }

    // 4、投票人查询： 投票服务-->写票软件
    public SearchVoter onSearchVoterResult(String message) {
        // 解析字符串 selectedElection 对象
        // json转为简单Bean
        mSearchVoter = gson.fromJson(message, SearchVoter.class);
        mSearchVoterResult = message;
        cancelLatch();
        return mSearchVoter;
    }

    // ///////////////========= 寫票軟件 --> 投票服務器
    private SelectedElection election;

    // 1、获取投票信息
    public SelectedElection selectedElection() {
        CommandBase commandbase4 = new CommandBase();
        commandbase4.setType("selectedElection");
        String cmd4 = gson.toJson(commandbase4);
        System.out.println(" ws send selectedelection----------------------------" + cmd4);
        election = null;
        clientSendMsg(cmd4);
        launchTimer(20);
        return election;

    }

    // 2、写票操作
    public int writeRecordResult;

    public int writeRecord(String dnCode, String electionId, ArrayList<Candidate> canList) {
        Gson gson = new Gson();
        WriteRecordBean recordInfo = new WriteRecordBean("writeRecord", dnCode, electionId, canList);
        String cmd = gson.toJson(recordInfo, WriteRecordBean.class);
        LogUtils.i("writeRecord " + cmd);
        writeRecordResult = -1;
        clientSendMsg(cmd);
        launchTimer(20);
        return writeRecordResult;
    }


    // 3、读已写的票
    public String readRecordResult;

    public String readRecord(String cardId, String electionId) {
        ReadRecordBean info = new ReadRecordBean("readRecord", cardId, electionId);
        String cmd = gson.toJson(info);
        // Toast.makeText(app.context4, cmd4, Toast.LENGTH_SHORT).show();
        readRecordResult = null;
        clientSendMsg(cmd);
        launchTimer(30);
        return readRecordResult;
    }

    public void senddata(String str) {
        System.out.println(" senddata --------------------------------------------------" + str);
        clientSendMsg(str);
    }

    SearchVoter mSearchVoter = null;

    // 4、投票人查询
    private String mSearchVoterResult;

    public String searchVoter(int regionId, String filter, int limit, int skip) {
        SearchVoteBean info = new SearchVoteBean("searchVoter", regionId, filter, limit, skip);
        String cmd = gson.toJson(info);
        mSearchVoterResult = null;
        clientSendMsg(cmd);
        launchTimer(30);
        return mSearchVoterResult;
    }


    /**
     * 保存错误信息到文件中
     *
     * @param ex
     * @return 返回文件名称, 便于将文件传送到服务器
     */
    private String exceptionstring(Throwable ex) {

        StringBuffer sb = new StringBuffer();
        Writer writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        ex.printStackTrace(printWriter);
        Throwable cause = ex.getCause();
        while (cause != null) {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }
        printWriter.close();
        String result = writer.toString();
        return result;
    }


}
